package org.melanesia.beans;

import java.sql.Types;
import java.util.HashMap;
import java.util.Map;

import org.melanesia.converters.JavaToJavaConverter;
import org.melanesia.converters.JavaToJdbcConverter;
import org.melanesia.converters.java.NumberToNumberConverter;
import org.melanesia.converters.jdbc.PassThruJdbcConverter;


public class Mapper {

    private class ClassPair {
        
        private Class<?> fromClass;
        private Class<?> toClass;

        public ClassPair(Class<?> fromClass, Class<?> toClass) {
            this.fromClass = fromClass;
            this.toClass = toClass;
        }
        
        public int hashCode() {
            return (fromClass.getName() + " " + toClass.getName()).hashCode();
        }
        
        public boolean equals(Object object) {
            if (object instanceof ClassPair) {
                return equals((ClassPair)object);
            }
            
            return false;
        }
        
        public boolean equals(ClassPair classPair) {
            return classPair.fromClass.equals(fromClass) && classPair.toClass.equals(toClass);
        }
    }
    
    private Map<Class<?>, JavaToJdbcConverter> javaToJdbcConverters = new HashMap<Class<?>, JavaToJdbcConverter>();
    private Map<ClassPair, JavaToJavaConverter> javaToJavaConverters = new HashMap<ClassPair, JavaToJavaConverter>();
    
    public Mapper() {
    	
    	// Java to JDBC converters (pass thru)
    	registerConverter(String.class, 	new PassThruJdbcConverter(Types.VARCHAR));
    	registerConverter(java.util.Date.class,		
    										new PassThruJdbcConverter(Types.DATE));
    	
    	registerConverter(Long.class, 		new PassThruJdbcConverter(Types.BIGINT));
    	registerConverter(Integer.class, 	new PassThruJdbcConverter(Types.INTEGER));
    	registerConverter(Short.class, 		new PassThruJdbcConverter(Types.SMALLINT));
    	registerConverter(Byte.class, 		new PassThruJdbcConverter(Types.SMALLINT));
    	registerConverter(Float.class, 		new PassThruJdbcConverter(Types.FLOAT));
    	registerConverter(Double.class, 	new PassThruJdbcConverter(Types.DOUBLE));
    	registerConverter(Character.class, 	new PassThruJdbcConverter(Types.CHAR));
    	registerConverter(Boolean.class, 	new PassThruJdbcConverter(Types.BOOLEAN));

    	registerConverter(long.class, 		new PassThruJdbcConverter(Types.BIGINT));
    	registerConverter(int.class, 		new PassThruJdbcConverter(Types.INTEGER));
    	registerConverter(short.class, 		new PassThruJdbcConverter(Types.SMALLINT));
    	registerConverter(byte.class, 		new PassThruJdbcConverter(Types.SMALLINT));
    	registerConverter(float.class, 		new PassThruJdbcConverter(Types.FLOAT));
    	registerConverter(double.class, 	new PassThruJdbcConverter(Types.DOUBLE));
    	registerConverter(char.class, 		new PassThruJdbcConverter(Types.CHAR));
    	registerConverter(boolean.class, 	new PassThruJdbcConverter(Types.BOOLEAN));
    	
    	// Number converters
    	for (Class<?>[] pair: NumberToNumberConverter.getSupportedConversions()) {
    		registerConverter(pair[0], pair[1], new NumberToNumberConverter(pair[1]));
    	}
    	
    	
    }
    
    public void registerConverter(Class<?> javaClass, JavaToJdbcConverter converter) {
        javaToJdbcConverters.put(javaClass, converter);
    }
    
    public void registerConverter(Class<?> fromClass, Class<?> toClass, JavaToJavaConverter converter) {
        javaToJavaConverters.put(new ClassPair(fromClass, toClass), converter);
    }
    
    public JavaToJdbcConverter findJavaToJdbcConverter(Class<?> clazz) {
        return javaToJdbcConverters.get(clazz);
    }
    
    public JavaToJavaConverter findJavaToJavaConverter(Class<?> fromClass, Class<?> toClass) {
        return javaToJavaConverters.get(new ClassPair(fromClass, toClass));
    }
}
